package concurrent;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 自己实现阻塞队列
 * 队列方式实现
 * Created by yzy on 2021-01-28 17:40
 */
public class MyBlockingQueue<T> {

    private ReentrantLock lock;
    private Condition notEmpty;
    private Condition notFull;
    private Queue<T> queue;
    private int  size;
    private int capacity;


    public MyBlockingQueue(int capacity){
        this.lock = new ReentrantLock();
        this.notEmpty = lock.newCondition();
        this.notFull = lock.newCondition();
        this.queue = new LinkedList<>();
        this.size = 0;
        this.capacity = capacity;
    }


    public void put(T t){
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            while(size >= capacity){
                System.out.println("queue is full, current element:" + queue);
                notFull.await();
            }
            queue.add(t);
            size++;
            notEmpty.signalAll();
            System.out.println("queue add:" + t);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public void offer(T t, long time, TimeUnit timeUnit){
        long nanos = timeUnit.toNanos(time);
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            while(size >= capacity){
                System.out.println("queue is full, current element:" + queue);
                notFull.awaitNanos(nanos);
            }
            queue.add(t);
            size++;
            notEmpty.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }


    }


    public T take(){
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            while(size <= 0){
                System.out.println("queue is empty...");
                notEmpty.await();
            }
            T t = queue.poll();
            size--;
            notFull.signalAll();
            return t;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return null;
    }

    public T poll(long time, TimeUnit timeUnit){
        final ReentrantLock lock = this.lock;
        long nanos = timeUnit.toNanos(time);
        lock.lock();
        try {
            while(size <= 0){
                System.out.println("queue is empty...");
                notEmpty.awaitNanos(nanos);
            }
            T t = queue.poll();
            size--;
            notFull.signalAll();
            return t;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return null;
    }






}
